April 29, 2022
이펙티브 타입스크립트 아이템 15 부분을 읽으면서 정리한 내용입니다.
객체 타입인데 키의 이름을 마땅히 모를 때 유용한 방법.
예시를 보자.
// [property: string] : string 이 부분이 인덱스 시그니처이다.
type Rocket = { [property: string]: string };
const rocket: Rocket = {
name: 'Falcon 9',
variant: 'v1.0',
thrust: '4,940 kN',
};
property
라는 키의 이름은 위치만 표시하는 용도이다. 원하는 대로 네이밍하면 된다.type Rocket = { [property: string] : {} }
로 변경해도 문제가 없다. number 로 바꾸면 에러가 뜬다.thrust
만 number 타입을 가지고 싶을 때 구현할 방법이 없다.function parseCSV(input: string): { [columnName: string]: string }[] {
const lines = input.split('\n');
const [header, ...rows] = lines;
return rows.map(rowStr => {
const row: { [columnName: string]: string } = {};
rowStr.split(',').forEach((cell, i) => {
row[header[i]] = cell;
});
return row;
});
}
우선 위 코드를 파악해보자
[{ 가: '나' }, { 가: '다' }, { 가: '라' }];
만약 열 이름을 알고 있는 특정한 상황이라면 단언문 as를 사용해준다.
interface ProductRow {
productId: string;
name: string;
price: string;
}
declare let csvData: string;
const products = (parseCSV(csvData) as unknown) as ProductRow[]; // as unknown !!
as unknown 이 없으면 알아서 사용하라고 에러가 떠주기 때문에 외울 필요는 없다.
[columnName: string]: string
과 ProductRow[]
두 형식이 충분히 겹치지 않는다고 보는 것이기 때문에 as가 필요하다.
키의 이름이 제한되었다면 인덱스 시그니처를 쓰지 말자.
아래와 같이 키의 이름이 a, b, c, d 중 하나일때는 이렇게 쓰는게 좋다.
interface Row2 {
a: number;
b?: number;
c?: number;
d?: number;
}
키의 이름이 제한되었지만 너무 많을 경우는 두가지 대안이 있다.
type Vec3D = Record<'x' | 'y' | 'z', number>;
// Type Vec3D = {
// x: number;
// y: number;
// z: number;
// }
type Vec3D = { [k in 'x' | 'y' | 'z']: number };
// 위의 record 예제와 같다.
type ABC = { [k in 'a' | 'b' | 'c']: k extends 'b' ? string : number };
// Type ABC = {
// a: number;
// b: string;
// c: number;
// }
위에 ABC 타입을 보면 매핑된 타입을 사용하면 키마다 별도의 타입을 사용하는 것도 가능해진다 !